using System;

namespace GURUCORE.Lib.Core.Security.Cryptography
{
	public static class HexEncoding
	{
		public static int GetByteCount(string p_sHexString)
		{
			int nHexChars = 0;
			char cChar;
			// remove all none A-F, 0-9, characters
			for (int nIdx = 0; nIdx < p_sHexString.Length; nIdx++)
			{
				cChar = p_sHexString[nIdx];
				if (IsHexDigit(cChar))
					nHexChars++;
			}
			if (nHexChars % 2 != 0)
			{
				nHexChars--;
			}
			return nHexChars / 2; // 2 characters per byte
		}

		public static byte[] GetBytes(string p_sHexString)
		{
			int nDiscarded = 0;
			string sNewString = "";
			char c;
			// remove all none A-F, 0-9, characters
			for (int i=0; i<p_sHexString.Length; i++)
			{
				c = p_sHexString[i];
				if (IsHexDigit(c))
					sNewString += c;
				else
					nDiscarded++;
			}
			// if odd number of characters, discard last character
			if (sNewString.Length % 2 != 0)
			{
				nDiscarded++;
				sNewString = sNewString.Substring(0, sNewString.Length-1);
			}

			int nByteLength = sNewString.Length / 2;
			byte[] arrBytes = new byte[nByteLength];
			string hex;
			int j = 0;
			for (int i=0; i<arrBytes.Length; i++)
			{
				hex = new String(new Char[] {sNewString[j], sNewString[j+1]});
				arrBytes[i] = HexToByte(hex);
				j = j+2;
			}
			return arrBytes;
		}

		public static string ToString(byte[] p_arrBytes)
		{
			string p_sHexString = "";
			for (int i=0; i<p_arrBytes.Length; i++)
			{
				p_sHexString += p_arrBytes[i].ToString("X2");
			}
			return p_sHexString;
		}
		/// <summary>
		/// Determines if given string is in proper hexadecimal string format
		/// </summary>
		/// <param name="p_sHexString"></param>
		/// <returns></returns>
		public static bool InHexFormat(string p_sHexString)
		{
			bool bHexFormat = true;

			foreach (char cDigit in p_sHexString)
			{
				if (!IsHexDigit(cDigit))
				{
					bHexFormat = false;
					break;
				}
			}
			return bHexFormat;
		}

		/// <summary>
		/// Returns true is c is a hexadecimal digit (A-F, a-f, 0-9)
		/// </summary>
		/// <param name="c">Character to test</param>
		/// <returns>true if hex digit, false if not</returns>
		public static bool IsHexDigit(Char p_c)
		{
			int nNumChar;
			int nNumA = Convert.ToInt32('A');
			int nNum1 = Convert.ToInt32('0');
			p_c = Char.ToUpper(p_c);
			nNumChar = Convert.ToInt32(p_c);
			if (nNumChar >= nNumA && nNumChar < (nNumA + 6))
				return true;
			if (nNumChar >= nNum1 && nNumChar < (nNum1 + 10))
				return true;
			return false;
		}
		/// <summary>
		/// Converts 1 or 2 character string into equivalant byte value
		/// </summary>
		/// <param name="hex">1 or 2 character string</param>
		/// <returns>byte</returns>
		private static byte HexToByte(string p_sHex)
		{
			if (p_sHex.Length > 2 || p_sHex.Length <= 0)
				throw new ArgumentException("hex must be 1 or 2 characters in length");
			byte newByte = byte.Parse(p_sHex, System.Globalization.NumberStyles.HexNumber);
			return newByte;
		}
	
	}	// end class
}	// end namespace
